﻿namespace Atomic.Events
{
    using System;
    using System.Collections.Generic;

    using Atomic.Common;

    /// <summary>
    /// 事件管理器。
    /// </summary>
    public class EventManager
    {
        #region 字段

        /// <summary>
        /// 当前命令总线
        /// </summary>
        private static EventManager _current = new EventManager();

        /// <summary>
        /// 通用事件处理器字典缓存。
        /// </summary>
        private readonly static IDictionary<Type, IEventManager> _genericEventManagers = new Dictionary<Type, IEventManager>();

        #endregion

        /// <summary>
        /// 当前命令总线
        /// </summary>
        public static EventManager Current
        {
            get
            {
                return _current;
            }
        }

        /// <summary>
        /// 填充事件处理器
        /// </summary>
        /// <param name="eventHandler">事件处理器</param>
        public void EventHandlersWith(IEventHandler eventHandler)
        {
            Check.NotNull(eventHandler, "eventHandler");

            IEventManager eventManager = this.CreateGenericEventManager(eventHandler.EventType);

            if (eventManager != null)
            {
                eventManager.EventHandlersWith(eventHandler);
            }
        }

        /// <summary>
        /// 填充事件处理器
        /// </summary>
        /// <typeparam name="TEvent">事件类型</typeparam>
        /// <param name="eventHandlers">事件处理器</param>
        /// <returns>事件处理器组</returns>
        public IEventHandlerGroup<TEvent> EventHandlersWith<TEvent>(params IEventHandler<TEvent>[] eventHandlers) where TEvent : IEvent
        {
            return this.GetEventManager<TEvent>().EventHandlersWith(eventHandlers);
        }

        /// <summary>
        /// 发布事件
        /// </summary>
        /// <param name="_event">事件信息</param>
        public void Publish(object _event)
        {
            IEventManager eventManager = this.CreateGenericEventManager(_event.GetType());

            if (eventManager != null)
            {
                eventManager.Publish(_event);
            }
        }

        /// <summary>
        /// 发布事件
        /// </summary>
        /// <typeparam name="TEvent">事件类型</typeparam>
        /// <param name="_event">事件信息</param>
        public void Publish<TEvent>(TEvent _event) where TEvent : IEvent
        {
            this.GetEventManager<TEvent>().Publish(_event);
        }

        /// <summary>
        /// 清理事件处理器。
        /// </summary>
        /// <typeparam name="TEvent">事件信息。</typeparam>
        public void Clear<TEvent>() where TEvent : IEvent
        {
            this.GetEventManager<TEvent>().Clear();
        }

        /// <summary>
        /// 获得事件处理器
        /// </summary>
        /// <typeparam name="TEvent">事件类型</typeparam>
        /// <returns>事件管理器</returns>
        private IEventManager<TEvent> GetEventManager<TEvent>() where TEvent : IEvent
        {
            if (EventManagerContainer<TEvent>.Instance == null)
            {
                EventManagerContainer<TEvent>.Instance = new DefaultEventManager<TEvent>();
            }

            return EventManagerContainer<TEvent>.Instance;
        }

        #region 创建通用事件处理器。 IEventManager CreateGenericEventManager(Type modelType)

        /// <summary>
        /// 创建通用事件处理器。
        /// </summary>
        /// <param name="modelType">模型类型。</param>
        /// <returns>通用事件处理器。</returns>
        private IEventManager CreateGenericEventManager(Type modelType)
        {
            IEventManager eventManager = null;

            if (_genericEventManagers.ContainsKey(modelType))
            {
                eventManager = _genericEventManagers[modelType];
            }
            else
            {
                Type clientType = typeof(GenericEventManager<>).MakeGenericType(modelType);
                eventManager = Activator.CreateInstance(clientType) as IEventManager;

                if (eventManager != null)
                {
                    _genericEventManagers[modelType] = eventManager;
                }
            }

            return eventManager;
        }

        #endregion
    }
}